package cn.sangedon.review.common.domain.bean;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.sangedon.review.common.domain.data.TradingDate;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

/**
 * 交易日期列表对象
 * 可根据当前时间点往前走，也可往后走
 *
 * @author sangedon
 */
@Data
@Slf4j
public class TradeDateList implements Serializable {

    private static final long serialVersionUID = -7881487858965983358L;

    /**
     * 交易日列表大小
     */
    private Integer size;

    /**
     * 交易日
     */
    private Map<String, TradeDayNode> nodeMap;

    /**
     * 当前交易日
     */
    private String current;

    public TradeDateList() {
        init(new ArrayList<>());
    }

    public TradeDateList(List<TradingDate> timeStrList) {
        init(timeStrList);
    }

    private TradeDateList(Integer size, Map<String, TradeDayNode> nodeMap) {
        this.size = size;
        this.nodeMap = nodeMap;
    }

    private void init(List<TradingDate> tradeDays) {
        try {
            if (CollectionUtils.isEmpty(tradeDays)) {
                new TradeDateList(0, new HashMap<>());
                return;
            }
            nodeMap = new HashMap<>();
            tradeDays.stream().sorted((e1, e2) -> DateUtil.parse(e1.getTradingDate(), DatePattern.NORM_DATE_FORMAT)
                                                          .compareTo(DateUtil.parse(e2.getTradingDate(), DatePattern.NORM_DATE_FORMAT)))
                     .forEach(e -> e.setTimeMillis(DateUtil.parse(e.getTradingDate(), DatePattern.NORM_DATE_FORMAT).getTime()));
            current = tradeDays.get(0).getTradingDate();
            size = tradeDays.size();
            for (int i = 0; i < size; i++) {
                TradingDate tradingDate = tradeDays.get(i);
                TradeDayNode dayNode = new TradeDayNode(tradingDate);
                nodeMap.put(tradingDate.getTradingDate(), dayNode);
            }

            for (int i = 0; i < size; i++) {
                TradeDayNode dayNode = nodeMap.get(tradeDays.get(i).getTradingDate());
                if (i > 0) {
                    dayNode.setPre(nodeMap.get(tradeDays.get(i - 1).getTradingDate()));
                }
                if (i < size - 1) {
                    dayNode.setPost(nodeMap.get(tradeDays.get(i + 1).getTradingDate()));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("初始化交易日失败:" + e.getLocalizedMessage());
        }
    }

    /**
     * 获取当前交易日对象,随机获取一个，请在只有一个元素时使用
     *
     * @return
     */
    public TradingDate current() {
        return nodeMap.get(current).getValue();
    }

    /**
     * 获取某个交易日对象
     *
     * @return
     */
    public TradingDate get(String time) {
        TradeDayNode tradeDayNode = nodeMap.get(time);
        if (tradeDayNode == null) {
            log.info("未获取到交易日:{}", time);
            return null;
        }
        return tradeDayNode.getValue();
    }

    /**
     * 获取前一个交易日对象
     *
     * @return
     */
    public TradingDate previous(String time) {
        TradeDayNode tradeDayNode = nodeMap.get(time);
        if (tradeDayNode == null) {
            log.info("未获取到交易日:{}", time);
            return null;
        }
        TradeDayNode pre = tradeDayNode.getPre();
        if (pre == null) {
            log.info("未获取到交易日:{} 的前一个交易日", time);
            return null;
        }
        current = pre.getValue().getTradingDate();
        return pre.getValue();
    }

    /**
     * 获取后一个交易日对象
     *
     * @return
     */
    public TradingDate behind(String time) {
        TradeDayNode tradeDayNode = nodeMap.get(time);
        if (tradeDayNode == null) {
            log.info("未获取到交易日:{}", time);
            return null;
        }
        TradeDayNode post = tradeDayNode.getPost();
        if (post == null) {
            log.info("未获取到交易日:{} 的后一个交易日", time);
            return null;
        }
        current = post.getValue().getTradingDate();
        return post.getValue();
    }
}
